package com.terry.sp.websocket;

import com.terry.sp.model.Device;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Component;

import javax.websocket.*;
import javax.websocket.server.PathParam;
import javax.websocket.server.ServerEndpoint;
import java.net.URI;
import java.util.HashMap;

/**
 * # WS client example
 * <p>
 * import asyncio
 * import websockets
 * <p>
 * <p>
 * async def hello():
 * name = "terry"
 * <p>
 * async with websockets.connect('ws://localhost:8080/websocket/'+name) as websocket:
 * while True:
 * number = input("What's your number? ")
 * if number != 'Q':
 * await websocket.send(number)
 * greeting = await websocket.recv()
 * print(f"< {greeting}")
 * else:
 * break
 * <p>
 * asyncio.get_event_loop().run_until_complete(hello())
 */

@Slf4j
@Component
@ServerEndpoint(value = "/websocket/{deviceId}")
public class DeviceServer extends Device {

    /**
     * 设备列表
     */
    private static HashMap<Integer, DeviceServer> webSocketSet = new HashMap<>();

    /**
     * 与某个客户端的连接会话，需要通过它来给客户端发送数据
     */
    private Session session;

    @OnOpen
    public void onOpen(Session session, @PathParam("deviceId") String deviceId) {
        log.debug("有新设备上线:" + deviceId);
        this.session = session;
        this.setId(Integer.parseInt(deviceId));
        webSocketSet.put(Integer.parseInt(deviceId), this);

        // 去服务器上查询自己的任务的工作留给http去做, 这里只做实时数据从服务器端往客户端发送的任务.
        // this.session.getAsyncRemote().sendText("1");
        log.debug("在线设备数：" + webSocketSet.keySet().size() + "");
    }

    @OnClose
    public void onClose() {
        webSocketSet.remove(this.getId());
        log.debug("一个连接关闭!");
    }

    @OnMessage
    public void onMessage(String message, Session session) {
        log.debug("收到消息:" + message);
        sendMessage("back==>" + message);
    }

    @OnError
    public void onError(Session session, Throwable error) {
        log.error("发生错误");
        error.printStackTrace();
    }

    /**
     * 实现服务器主动推送
     */
    private void sendMessage(String message) {
        // 异步发送消息
        this.session.getAsyncRemote().sendText(message);

        // 同步发送消息 注意，这里如果要发送多个消息，并且消息的顺序重要的时候，则要使用同步发送消息，也就是getBasicRemove()的方式来发送，如下:
        // this.session.getBasicRemote().sendText(message);
    }

    /**
     * 发送自定义消息到 指定客户端(by deviceId) or 所有客户端
     */
    public static void sendInfo(String message, @PathParam("deviceId") Integer deviceId) {

        if (deviceId > 0) {
            // 向指定指定设备发消息
            DeviceServer serverItem = webSocketSet.get(deviceId);
            if (serverItem != null) {
                log.debug("推送消息到设备:" + serverItem.getObjectName() + "，推送内容:" + message);
                serverItem.sendMessage(message);

            }
        } else {
            // 向所有设备发消息
            log.debug("向所有设备推送消息:" + message);
            for (DeviceServer srv : webSocketSet.values()) {
                srv.sendMessage(message);
            }
        }
    }

    /**
     * 查看设备状态
     *
     * @param deviceId device's id
     * @return return 1 when ok or 0 when fail.
     */
    public static int checkDeviceStatus(int deviceId) {
        DeviceServer deviceItem = webSocketSet.get(deviceId);
        return deviceItem != null ? 1 : 0;
    }
}
